using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using SendReceive;
using System.Runtime.InteropServices;

    public class sendCommand
    {
        Socket a = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//        public static ManualResetEvent allDone = new ManualResetEvent(false);
        public int port = 456;
        string IP ="";
        public static string endCommand="<EOF\x1A>";
        public static string separator="$";
        public static string separatorColumn = "\x1F";
        public sendCommand(string Ip, int Port, bool tryConnect)
        {
            IP = Ip;
            port = Port;
            if (tryConnect)
            {//try to connect immediately
                connect();
            }
        }
        public sendCommand(string Ip, int Port)
        {
            IP = Ip;
            port = Port;
        }
        ~sendCommand()
        {
            //try to release connection
            disconnect();
        }
        public bool setIP(string IPs,int thePort)
        {
            IP = IPs;
            port=thePort;
            return true;
        }
        public bool setIP(string IPs)
        {
            IP = IPs;
            return true;
        }
        public bool isConnected()
        {
            return a.Connected;
        }
        public bool connect()
        {
            if (a.Connected)
            {
                return true;
            }
            try{
            //IPAddress[] hostIP = (Dns.GetHostEntry(IP)).AddressList;
            //IPAddress current = null;
            //for (int i = 0; i < hostIP.Length; i++)
            //{
            //    if (hostIP[i].IsIPv6LinkLocal == false)
            //    {
            //        current = hostIP[i];
            //        break;
            //    }
            //}
            IPAddress current = null;
            IPAddress.TryParse(IP, out current);
            a.Connect(current, port);
                return true;
            }
            catch(Exception ex)
            {
                return false;
            }
        }
        public bool disconnect()
        {
            if( !a.Connected)
            {
                return false;
            }
            a.Disconnect(false);
            return true;
        }
        public bool forConnect()
        {
            if (a.Connected)
            {
                a.Disconnect(false); ;
            }
            try{
            a.Connect(IP, port);
            return true;
            }
            catch{
                return false;
            }
        }
        double[] latlon = {21.046295,105.805825, 21.046295, 105.804237, 21.046235,105.80295, 21.046315,105.801662, 21.046315,105.800504, 21.046295,105.799302, 21.046315,105.798315,
                            21.046275,105.79707, 21.046315,105.795955, 21.046335,105.794989, 21.046355,105.793573, 21.046315,105.7922, 21.046275,105.791041, 21.046275,105.789689,
                            21.046295,105.788251, 21.046235,105.786792, 21.046255,105.785398, 21.046135,105.784067, 21.046215,105.782608, 21.046195,105.781385, 21.045133,105.781235,
                            21.043972,105.781127, 21.04293,105.78102, 21.041789,105.780934, 21.040848,105.780891, 21.039546,105.780741, 21.038404,105.780655, 21.037143,105.78057,
                            21.035801,105.780376, 21.034659,105.780226, 21.033337,105.77999, 21.031695,105.779754, 21.030353,105.779454, 21.029111,105.779218, 21.027669,105.779003,
                            21.026568,105.77881, 21.025386,105.77866, 21.023944,105.778553, 21.022562,105.778831, 21.0215,105.779282, 21.020559,105.77984, 21.019658,105.78057,
                            21.018796,105.781278, 21.017915,105.781986, 21.016673,105.78293, 21.015632,105.78381, 21.01467,105.784604, 21.013528,105.785526, 21.012467,105.786342,
                            21.011625,105.787071, 21.010444,105.787994, 21.009202,105.789002, 21.00814,105.789882, 21.007018,105.790783, 21.005776,105.791813, 21.004474,105.792886,
                            21.003352,105.793766, 21.00181,105.794946, 21.00195,105.794817, 21.002291,105.794538, 21.000828,105.795826, 20.999747,105.796727, 20.998364,105.797714,
                            20.998104,105.79795, 20.996702,105.799045, 20.995339,105.800139, 20.994198,105.801083, 20.993056,105.802006, 20.991553,105.80325, 20.992435,105.804688,
                            20.993797,105.806662, 20.994939,105.80825, 20.99596,105.809859, 20.997002,105.811297, 20.998044,105.812863, 20.999286,105.814687, 21.000608,105.816661,
                            21.00183,105.818485, 21.003112,105.820223, 21.004394,105.821876, 21.006257,105.822884, 21.00816,105.823807, 21.009863,105.824772, 21.011906,105.82591,
                            21.013809,105.827154, 21.015932,105.828442, 21.017915,105.829557, 21.019698,105.830459, 21.021801,105.831467, 21.023724,105.832347, 21.025506,105.833227,
                            21.027589,105.834085, 21.029272,105.835244, 21.030533,105.836059, 21.031575,105.836317, 21.031875,105.834879, 21.032196,105.833098, 21.032937,105.832948,
                            21.032957,105.831617, 21.032797,105.830029, 21.032436,105.82827, 21.032076,105.826596, 21.031795,105.82488, 21.031515,105.823163, 21.031274,105.821318,
                            21.031034,105.819408, 21.030694,105.817369, 21.030513,105.815803, 21.030433,105.813936, 21.030233,105.81222, 21.029852,105.810331, 21.029572,105.808465,
                            21.029312,105.806662, 21.028831,105.805396, 21.028671,105.805117, 21.029071,105.804173, 21.029612,105.802757, 21.030213,105.801662, 21.031335,105.800139,
                            21.032336,105.799066, 21.033377,105.797993, 21.034379,105.796362, 21.03488,105.79471, 21.03544,105.793058, 21.036001,105.79117, 21.036382,105.789925,
                            21.038044,105.790354, 21.039906,105.790504, 21.041669,105.790311, 21.043872,105.790268};
        public int sendBinary()
        {
            int sentByte;
            byte[] byteData = new byte[56*2] { 0x33, 0x54, 0x43, 0x55, 0x0, 0x0, 0x23, 0x29, 0x40, 0x1F, 0x0, 0x0, 0xA, 0x34, 0xD, 0xF, 0xA, 0xD, 0x14, 0x3B, 0x45, 0x63, 0x69, 0x2F, 0x47, 0x13, 0x0, 0x80, 0xE1, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x32, 0x2D, 0xA, 0xF, 0xA, 0xD, 0x0, 0xD, 0xC, 0x0, 0xA, 0xC8, 0x1, 0xA1, 0x2A, 0xD, 0xA, 0x33, 0x54, 0x43, 0x55, 0x0, 0x0, 0x23, 0x2C, 0x40, 0x1F, 0x0, 0x0, 0x10, 0x16, 0x12, 0xE, 0xA, 0xD, 0x14, 0x3B, 0x44, 0x35, 0x69, 0x2F, 0x48, 0x28, 0x0, 0x80, 0xA1, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x2F, 0xF, 0x7, 0xA, 0xD, 0x0, 0x0, 0x78, 0x0, 0x0, 0x5B, 0x0, 0x0, 0x2A, 0xD, 0xA };
            if (!a.Connected)
            {
                connect();
            }
            sentByte = 0;
            if (a.Connected)
            {
                try
                {
                    sentByte = a.Send(byteData);
                }
                catch (Exception exx)
                {
                    sentByte = -1;
                }
            }
            //            disconnect();
            return sentByte;
        }
        public int sendDemo(int v, ref int countPa, UInt32 id, int add)
        {
            //reset the array index
            if (2 * countPa >= latlon.Length)
            {
                countPa = 0;
            }

            packet pa = new packet();
            //header
            pa.header0 = (byte)'3';
            pa.header1 = (byte)'T';
            pa.header2 = (byte)'C';
            pa.endPack0 = (byte)'*';
            pa.endPack1 = 13;
            pa.endPack2 = 10;
            pa.Packetcode = 0x55;
            //info
            pa.DeviceID = convert.rol32(id);
            pa.DriverID = convert.rol32(23);
            pa._year = (byte)(DateTime.Now.Year % 100);
            pa._month = (byte)(DateTime.Now.Month % 100);
            pa._day = (byte)(DateTime.Now.Day % 100);
            pa._hour = (byte)(DateTime.Now.Hour % 100);
            pa._min = (byte)(DateTime.Now.Minute % 100);
            pa._sec = (byte)(DateTime.Now.Second % 100);

            pa._hiredYear = (byte)(DateTime.Now.Year % 100);
            pa._hiredMonth = (byte)(DateTime.Now.Month % 100);
            pa._hiredDay = (byte)(DateTime.Now.Day % 100);
            pa._hiredHour = (byte)(DateTime.Now.Hour % 100);
            pa._hiredMin = (byte)(DateTime.Now.Minute % 100);

            pa._unhiredYear = (byte)(DateTime.Now.Year % 100);
            pa._unhiredMonth = (byte)(DateTime.Now.Month % 100);
            pa._unhiredDay = (byte)(DateTime.Now.Day % 100);
            pa._unhiredHour = (byte)(DateTime.Now.Hour % 100);
            pa._unhiredMin = (byte)(DateTime.Now.Minute % 100);
            convert.lat2Byte((float)latlon[2 * ((countPa +add)%latlon.Length)], ref pa.Latitude0, ref pa.Latitude1, ref pa.Latitude2, ref pa.Latitude3);
            convert.lat2Byte((float)latlon[2 * ((countPa + add) % latlon.Length) + 1], ref pa.Longitude0, ref pa.Longitude1, ref pa.Longitude2, ref pa.Longitude3);



            //convert to byte[] to sent
            int size = Marshal.SizeOf(pa);
            byte[] byteData = new byte[61];
            IntPtr ptr = Marshal.AllocHGlobal(61);

            Marshal.StructureToPtr(pa, ptr, true);
            Marshal.Copy(ptr, byteData, 0, 61);
            Marshal.FreeHGlobal(ptr);


            int sentByte = 0;
            //int i;
            //for (i = 0; i < 61; i++)
            //{
            //    byteData[i] = (byte)v;
            //}
            if (!a.Connected)
            {
                connect();
            }
            sentByte = 0;
            if (a.Connected)
            {
                try
                {
                    sentByte = a.Send(byteData);
                }
                catch (Exception exx)
                {
                    sentByte = -1;
                }
            }
            //            disconnect();
            return sentByte;
        }
        public int sendDemo(int v, ref int countPa)
        {
            //reset the array index
            if (2*countPa >= latlon.Length)
            {
                countPa = 0;
            }

            packet pa = new packet();
            //header
            pa.header0 = (byte)'3';
            pa.header1 = (byte)'T';
            pa.header2 = (byte)'C';
            pa.endPack0 = (byte)'*';
            pa.endPack1 = 13;
            pa.endPack2 = 10;
            pa.Packetcode = 0x55;
            //info
            pa.DeviceID = convert.rol32(1234);
            pa.DriverID = convert.rol32(23);
            pa._year = (byte)(DateTime.Now.Year % 100);
            pa._month = (byte)(DateTime.Now.Month % 100);
            pa._day = (byte)(DateTime.Now.Day % 100);
            pa._hour = (byte)(DateTime.Now.Hour % 100);
            pa._min = (byte)(DateTime.Now.Minute % 100);
            pa._sec = (byte)(DateTime.Now.Second % 100);

            pa._hiredYear = (byte)(DateTime.Now.Year % 100);
            pa._hiredMonth = (byte)(DateTime.Now.Month % 100);
            pa._hiredDay = (byte)(DateTime.Now.Day % 100);
            pa._hiredHour = (byte)(DateTime.Now.Hour % 100);
            pa._hiredMin = (byte)(DateTime.Now.Minute % 100);

            pa._unhiredYear = (byte)(DateTime.Now.Year % 100);
            pa._unhiredMonth = (byte)(DateTime.Now.Month % 100);
            pa._unhiredDay = (byte)(DateTime.Now.Day % 100);
            pa._unhiredHour = (byte)(DateTime.Now.Hour % 100);
            pa._unhiredMin = (byte)(DateTime.Now.Minute % 100);
            convert.lat2Byte((float)latlon[2 * countPa], ref pa.Latitude0, ref pa.Latitude1, ref pa.Latitude2, ref pa.Latitude3);
            convert.lat2Byte((float)latlon[2 * countPa + 1], ref pa.Longitude0, ref pa.Longitude1, ref pa.Longitude2, ref pa.Longitude3);
            


            //convert to byte[] to sent
            int size = Marshal.SizeOf(pa);
            byte[] byteData = new byte[61];
            IntPtr ptr = Marshal.AllocHGlobal(61);

            Marshal.StructureToPtr(pa, ptr, true);
            Marshal.Copy(ptr, byteData, 0, 61);
            Marshal.FreeHGlobal(ptr);


            int sentByte = 0;
            //int i;
            //for (i = 0; i < 61; i++)
            //{
            //    byteData[i] = (byte)v;
            //}
            if (!a.Connected)
            {
                connect();
            }
            sentByte = 0;
            if (a.Connected)
            {
                try
                {
                    sentByte = a.Send(byteData);
                }
                catch (Exception exx)
                {
                    sentByte = -1;
                }
            }
            //            disconnect();
            return sentByte;
        }
        public int sendDemo(int v)
        {
            packet pa = new packet();
            //header
            pa.header0 = (byte)'3';
            pa.header1 = (byte)'T';
            pa.header2 = (byte)'C';
            pa.endPack0 = (byte)'*';
            pa.endPack1 = 13;
            pa.endPack2 = 10;
            pa.Packetcode=0x55;
            //info
            pa.DeviceID=1234;
            pa.DriverID=23;
            pa._year =(byte) (DateTime.Now.Year % 100);
            pa._month = (byte)(DateTime.Now.Month % 100);
            pa._day = (byte)(DateTime.Now.Day % 100);
            pa._hour = (byte)(DateTime.Now.Hour % 100);
            pa._min = (byte)(DateTime.Now.Minute% 100);
            pa._sec = (byte)(DateTime.Now.Second% 100);

            pa._hiredYear = (byte)(DateTime.Now.Year % 100);
            pa._hiredMonth = (byte)(DateTime.Now.Month % 100);
            pa._hiredDay = (byte)(DateTime.Now.Day % 100);
            pa._hiredHour = (byte)(DateTime.Now.Hour % 100);
            pa._hiredMin = (byte)(DateTime.Now.Minute % 100);

            pa._unhiredYear = (byte)(DateTime.Now.Year % 100);
            pa._unhiredMonth = (byte)(DateTime.Now.Month % 100);
            pa._unhiredDay = (byte)(DateTime.Now.Day % 100);
            pa._unhiredHour = (byte)(DateTime.Now.Hour % 100);
            pa._unhiredMin = (byte)(DateTime.Now.Minute % 100);

//convert to byte[] to sent
            int size = Marshal.SizeOf(pa);
            byte[] byteData = new byte[61];
            IntPtr ptr = Marshal.AllocHGlobal(61);

            Marshal.StructureToPtr(pa, ptr, true);
            Marshal.Copy(ptr, byteData, 0, 61);
            Marshal.FreeHGlobal(ptr);


            int sentByte = 0;
            //int i;
            //for (i = 0; i < 61; i++)
            //{
            //    byteData[i] = (byte)v;
            //}
            if (!a.Connected)
            {
                connect();
            }
            sentByte = 0;
            if (a.Connected)
            {
                try
                {
                    sentByte = a.Send(byteData);
                }
                catch (Exception exx)
                {
                    sentByte = -1;
                }
            }
//            disconnect();
            return sentByte;
        }
        public int sendText(string cm)
        {
            int sentByte=0;
            byte[] byteData = Encoding.Unicode.GetBytes(cm);
            if (!a.Connected)
            {
                connect();
            }
            sentByte = a.Send(byteData);
            disconnect();
            return sentByte;
        }

        #region client message to server
        //LG:+{group code}+{name of group}: group code: 1, 2, 3, 4, 0: for control server; name of group: name asigned
        public int login(string computer, string name, string IP, string port)
        {
            string fulText;
            fulText = "LG" +computer+ name + sendCommand.separator +IP + sendCommand.separator + port+sendCommand.endCommand;
            return sendText(fulText);
        }
        //CA: continue to answer
        public int continueAnswer(string computer)
        {
            string fulText;
            fulText = "CA" + computer +  sendCommand.endCommand;
            return sendText(fulText);
        }
        //SS: code: stage to show
        public int showStage(string computer, string code)
        {
            string fulText;
            fulText = "SS" + computer + code + sendCommand.endCommand;
            return sendText(fulText);
        }
        //ES: end last showed form
        public int endShow(string computer)
        {
            string fulText;
            fulText = "SS" + computer+sendCommand.endCommand;
            return sendText(fulText);

        }
        //QL: show the question list
        public int questionList(string computer)
        {
            string fulText;
            fulText = "QL" + computer +  sendCommand.endCommand;
            return sendText(fulText);
        }
        //IA: introduce all
        public int introduceAll(string computer)
        {
            string fulText;
            fulText = "IA" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //DQ: disable question
        public int disableQuestion(string computer, string status, string questionNumber)
        {
            string fulText;
            fulText = "DQ" + computer + status + questionNumber +sendCommand.endCommand;
            return sendText(fulText);
        }
        //SC: show the crossword
        public int showCrossword(string computer)
        {
            string fulText;
            fulText = "SC" + computer +  sendCommand.endCommand;
            return sendText(fulText);
        }
        //SQ: code: question number(00) (to disable in array), info: question$A1$A2, to client
        public int showQuestion(string computer, string code)
        {
            string fulText;
            fulText = "SQ" + computer + code+sendCommand.endCommand;
            return sendText(fulText);
        }
        //MA: mark for the question to group by mark
        public int markAnswer(string computer, string group,string mark)
        {
            string fulText;
            fulText = "MA" + computer +group+ mark + sendCommand.endCommand;
            return sendText(fulText);
        }
        //SG: set mark
        public int stopGrop(string computer, string group)
        {
            string fulText;
            fulText = "SG" + computer + group+ sendCommand.endCommand;
            return sendText(fulText);
        }
        //MS: set mark
        public int markSet(string computer, string group, string mark)
        {
            string fulText;
            fulText = "MS" + computer + group + mark + sendCommand.endCommand;
            return sendText(fulText);
        }
        //AC: allow continue to answer
        public int allowContinue(string computer)
        {
            string fulText;
            fulText = "AC" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //SM: show mark list of all canditates
        public int showMarklist(string computer)
        {
            string fulText;
            fulText = "SM" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //AA: ask for answer,
        public int AskForAnswer(string computer,string time)
        {
            string fulText;
            fulText = "AA" + computer +time.ToString()+ sendCommand.endCommand;
            return sendText(fulText);
        }
        //AA: ask for answer,
        public int emergencyAnswer(string computer, string time)
        {
            string fulText;
            fulText = "EA" + computer + time+ sendCommand.endCommand;
            return sendText(fulText);
        }
        //AF: answer for the question: code :full answer then 
        public int answerFullQuestion(string computer, string code, string remainTime)
        {
            string fulText;
            while (remainTime.Length < 3)
                remainTime = "0" + remainTime;
            fulText = "AF" + computer + remainTime + code + sendCommand.endCommand;
            return sendText(fulText);
        }
        //AQ: answer for the question: code : A, B, C, D, then 
        public int answerQuestion(string computer, string code,string remainTime)
        {
            string fulText;
            fulText = "AQ" + computer+code+remainTime + sendCommand.endCommand;
            return sendText(fulText);
        }
        //SL: Send login reply again, in case raising error
        public int sendLoginReply(string computer)
        {
            string fulText;
            fulText = "SL" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //DQ: Disable question in case raising error
        public int disableQuestion(string computer, string code)
        {
            string fulText;
            fulText = "DQ" + computer + code+ sendCommand.endCommand;
            return sendText(fulText);
        }
        //AF: Answer full text question
        public int answerFulltext(string computer, string code)
        {
            string fulText;
            fulText = "AF" + computer + code + sendCommand.endCommand;
            return sendText(fulText);
        }
        //SD: stop count down
        public int stopCountDown(string computer)
        {
            string fulText;
            fulText = "SD" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //CD: start to count down
        public int countDown(string computer)
        {
            string fulText;
            fulText = "CD" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //SA: show all the ansers of candidate
        public int showAnswer(string computer)
        {
            string fulText;
            fulText = "SA" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //CF: Close current form
        public int closeForm(string computer)
        {
            string fulText;
            fulText = "CF" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //CS: Close current form on server only
        public int closeFormServer(string computer)
        {
            string fulText;
            fulText = "CS" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }

        #endregion 
        #region server send to client
        //LR code: number of stage, info: {number question of stage 1},{number question of stage 2}, ...
        public int loginReply(string computer,string code, string timeUp, string info)
        {
            string fulText;
            fulText = "LR"+ computer + code + timeUp+separator+ info + sendCommand.endCommand;
            return sendText(fulText);
        }
        //QC question content, to send question content to client and require to show. code is number of answer
        //code(3): second to count down, Q, A1, A2, A3, A4
        public int questionContent(string computer, string code,string Q, params string [] A)
        {
            string fulText;
            int i;
            fulText = "QC" + computer + code + Q;
            for (i = 0; i < A.Length; i++)
            {
                fulText += sendCommand.separator + A[i];
            }
            fulText += sendCommand.endCommand;
            return sendText(fulText);
        }
        //AL: allow answer
        public int allowAnswer(string computer)
        {
            string fulText;
            fulText = "AL" + computer + sendCommand.endCommand;
            return sendText(fulText);
        }
        //QC question content, to send question content to client and require to show. code is number of answer
        //code(3): second to count down, Q, A1, A2, A3, A4
        public int showQuestion(string computer, string code, string info)
        {
            string fulText;
            fulText = "SQ" + computer + code + info + sendCommand.endCommand;
            return sendText(fulText);
        }

        #endregion
    }
